public interface HeatmapService {
    /**
     * 获取热力数据
     * @param bounds 地理边界 {swLat, swLng, neLat, neLng}
     * @param zoomLevel 地图缩放级别
     * @param timeRange 时间范围
     */
    HeatmapResponse getHeatmapData(BoundingBox bounds, 
                                  int zoomLevel,
                                  TimeRange timeRange);
    
    /**
     * 预生成热力网格数据（定时任务）
     */
    void precomputeHeatmapCache();
}

@Service
public class HeatmapServiceImpl implements HeatmapService {
    
    // 使用空间数据库函数计算
    private static final String HEATMAP_QUERY = """
        SELECT FLOOR(latitude * 100) AS lat_grid, 
               FLOOR(longitude * 100) AS lng_grid,
               COUNT(*) AS point_count,
               AVG(temperature) AS avg_temp
        FROM temperature
        WHERE MBRContains(ST_GeomFromText(?), ST_Point(longitude, latitude))
          AND report_time BETWEEN ? AND ?
        GROUP BY lat_grid, lng_grid
        """;
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Override
    public HeatmapResponse getHeatmapData(BoundingBox bounds, 
                                        int zoomLevel,
                                        TimeRange timeRange) {
        // 根据zoomLevel动态调整网格精度
        int gridSize = calculateGridSize(zoomLevel);
        
        // 执行空间查询
        List<HeatPoint> points = jdbcTemplate.query(
            HEATMAP_QUERY,
            new Object[]{
                String.format("POLYGON((%s %s, %s %s, %s %s, %s %s))", 
                    bounds.getSwLng(), bounds.getSwLat(),
                    bounds.getNeLng(), bounds.getSwLat(),
                    bounds.getNeLng(), bounds.getNeLat(),
                    bounds.getSwLng(), bounds.getNeLat()),
                timeRange.getStart(),
                timeRange.getEnd()
            },
            (rs, rowNum) -> new HeatPoint(
                rs.getDouble("lat_grid") / 100 + 0.005,
                rs.getDouble("lng_grid") / 100 + 0.005,
                rs.getInt("point_count"),
                rs.getDouble("avg_temp")
            ));
        
        return new HeatmapResponse(points, gridSize);
    }
    
    @Scheduled(cron = "0 0/5 * * * ?") // 每5分钟执行
    public void precomputeHeatmapCache() {
        // 生成不同层级的聚合数据
        generateHeatmapCache(14); // 城市级
        generateHeatmapCache(16); // 校区级
        generateHeatmapCache(18); // 建筑级
    }
}